/* 
iterator迭代器：为各种不同的数据结构，提供统一的遍历/迭代“机制”
  iterator规范/机制：
    + 数据结构必须具备next方法
    + 每一次执行next都是为了迭代到数据中的每个成员
      返回一个对象
      + value：当前迭代的这一项的值
      + done：是否迭代完成
*/

/* 
class Iterator {
  constructor(assemble) {
    this.assemble = assemble
    this.index = -1
  }
  next() {
    if (this.index === this.assemble.length - 1) {
      return {
        value: undefined,
        done: true
      }
    }
    let value = this.assemble[++this.index],
      done = false
    return {
      value,
      done
    }
  }
}
let itor = new Iterator([10, 20, 30, 40])
console.log(itor.next()) //->{value:10,done:false}
console.log(itor.next()) //->{value:20,done:false}
console.log(itor.next()) //->{value:30,done:false}
console.log(itor.next()) //->{value:40,done:false}
console.log(itor.next()) //->{value:undefined,done:true}
console.log(itor.next()) //->{value:undefined,done:true} 
*/

/* 
如何知道哪些数据结构具备迭代器规范呢？ 
  + 看数据结构是否具备 Symbol.iterator 属性「属性值是个函数」
  + 常用的具备迭代器规范的数据结构
    + 数组
    + 部分伪数组，例如：arguments、HTMLCollection元素集合、NodeList节点集合...
    + 字符串
    + Set/Map
    + ...
  + 普通对象是不具备迭代器规范的
  + 而具备迭代器规范的数据结构，可以使用 for/of 循环
*/

/* 
for/of 循环，只能获取数据的成员值 
  + 基于 for/of 迭代一个数据结构的时候，首先调用数据结构的 Symbol.iterator 方法「如果不具备这个方法，则直接报错，说明其不具备迭代器规范」
  + 执行 Symbol.iterator 方法，会获取到一个 itor 对象，对象中具备 next 方法
  + 每一轮循环都相当于在执行 next 方法「返回一个具备value/done的对象」
    把获取的 value 属性值，赋值给 value 这个变量
    根据 done 的值是true/false，决定循环是否继续

let itor = arr[Symbol.iterator]()
  第一轮循环 
    itor.next() -> {value:10,done:false}
  第二轮循环 
    itor.next() -> {value:20,done:false}
  第三轮循环 
    itor.next() -> {value:30,done:false}
  第四轮循环 
    itor.next() -> {value:undefined,done:true}
*/
/* 
let arr = [10, 20, 30]
arr[Symbol.iterator] = function iterator() {
  // this : arr
  let self = this,
    index = -1
  return {
    next() {
      if (index === self.length - 1) {
        return {
          value: undefined,
          done: true
        }
      }
      let value = self[++index],
        done = false
      return {
        value,
        done
      }
    }
  }
}
// let itor = arr[Symbol.iterator]()
for (let value of arr) {
  console.log(value) //10 20 30
} 
*/


//=========
// 面试题：普通对象是否可以使用 for/of 循环进行迭代？如果不行是为啥？如何让其可与基于 for/of 处理？

let obj = {
  name: '哈哈哈',
  age: 15,
  [Symbol('AA')]: 100
}
Object.defineProperty(obj, 'sex', {
  value: '男',
  // enumerable: false,
  // configurable: false,
  // writable: false
})

// 解决办法：手动为其设置一个 Symbol.iterator
Object.prototype[Symbol.iterator] = function iterator() {
  // 获取对象所有的私有成员
  let self = this,
    keys = Reflect.ownKeys(self),
    index = -1
  return {
    next() {
      if (index === keys.length - 1) {
        return { value: undefined, done: true }
      }
      let value = obj[keys[++index]],
        done = false
      return { value, done }
    }
  }
}
for (let value of obj) {
  console.log(value)
}

/* 
for (let value of obj) { //Uncaught TypeError: obj is not iterable
  console.log(value)
} 
// 原因：普通不具备迭代器规范，也就是不具备 Symbol.iterator 这个方法
*/